package org.redr.canvas;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.redr.canvas.utils.OutputSocketDataException;

public abstract class OutputSocket extends SignalSocket{
	
	private SignalClass _currentSignal = null;
	protected Object data = null;
	protected String memo = "Default memo for base output signal.";
	private List<InputSocket> connectedInputs	=	new ArrayList<InputSocket>();
	private Map<String, Object> 	dataCache	=	 new HashMap<String, Object>();
	
	public OutputSocket(RRW widget, String signalId, String n) {
		super(widget, signalId, n);
		// Settings
		// WidgetSettings settings = widget.settings;
		// settings.getSignalSettings(signalId)
		// TODO Auto-generated constructor stub
	}
	
	public void connectInput(InputSocket input){
		connectedInputs.add(input);
		String compatibleSignal = null;
		for ( String ocd : this.connectionTypes() ){
			if ( input.connectionTypes().contains(ocd) ) {
				compatibleSignal = ocd;
				break;
			}
		}
		
		try { 
			if ( !this.dataCache.containsKey(compatibleSignal) ) this.setDataCache(compatibleSignal);
			input.takeData( this.dataCache.get(compatibleSignal), compatibleSignal, this.getWidgetId() );
		} catch(OutputSocketDataException e) {
			e.printStackTrace();
			this.removeInput(input);
		}
	}
	
	private void setDataCache(String compatibleSignal) throws OutputSocketDataException {
		this.dataCache.put(compatibleSignal, this.getData(compatibleSignal));
		
	}

	public void removeInput(InputSocket input){
		connectedInputs.remove(input);
	}

	/**
	 * Abstract method for base class OutputSocket.  OutputSocket classes should implement 
	 * some way of taking in their specified data types, checking that they conform to the 
	 * specifications of that OutputSignal through some error checking
	 * @param data
	 */
	public abstract void setData(Object data) throws OutputSocketDataException;
	
	/**
	 * Abstract method, should simply return data, but left abstract so that developers 
	 * will be encouraged to do some error checking at this level.
	 * @return data - the data in the socket
	 */
	public abstract Object getData();
	
	/**
	 * Abstract method, should return data in the form that was requested by the signalType String.
	 * The signalType should be one of the signal types that was declared by this signal class during 
	 * construction in the connectionTypes String[].  If not then throw an error.  
	 * @param signalType
	 * @return
	 * @throws OutputSocketDataException
	 */
	public abstract Object getData(String signalType) throws OutputSocketDataException;
	
	public SignalClass currentSignal(){
		return _currentSignal;
	}
	
	public boolean hasSignal(){
		return data == null;
	}
	
	public String getMemo(){ return memo; }

}
